---
id: secrets
title: Working with secrets
slug: /guides/deploying/secrets
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

Database credentials are considered sensitive information and should be treated as such. In this guide,
we will show how to use Atlas to handle database credentials in a secure manner.  We will present two strategies
for handling database credentials, and show how to use Atlas to implement them: IAM Authentication and Secret Stores.

## Secret Stores

Secret stores are systems or services that allow users to store and retrieve sensitive information. The main features
of secret stores are encryption, access control, and auditing.  All cloud providers offer some form of secret store
service, and there are also many open-source alternatives.  

When working with secret stores, Atlas assumes that the secret store is already provisioned and configured. Atlas
supports the following secret stores:

* [AWS Secrets Manager](https://aws.amazon.com/secrets-manager)
* [AWS Systems Manager Parameter Store](https://aws.amazon.com/systems-manager/features/#Parameter_Store)
* [GCP Secret Manager](https://cloud.google.com/secret-manager)

Support for other secret stores is planned, if you have a specific request, please [open an issue](https://github.com/ariga/atlas/issues/new).

## IAM Authentication

IAM authentication is a mechanism that allows users to authenticate to a database using their cloud provider credentials.
The main advantage of IAM authentication is that it allows users to avoid storing database credentials altogether. Although
setting this up may be more cumbersome, it is considered a best practice for many cloud providers.  IAM authentication is also more secure than 
using passwords. Even strong passwords stored in encrypted form can be leaked and used by attackers. IAM authentication
allows users to avoid storing database credentials altogether.

IAM authentication is currently supported on GCP and AWS. Support for other cloud providers is planned as well,
if you have a specific request, please [open an issue](https://github.com/ariga/atlas/issues/new).

## Retrieving Credentials from a Secret Store

Atlas can retrieve information from a secret store at runtime using the `runtimevar` data source.  The `runtimevar`
data source uses the [`runtimevar` package](https://gocloud.dev/howto/runtimevar/) from the Go [CDK](https://gocloud.dev/).
To read more about using `runtimevar` with Atlas, view the [data source documentation](atlas-schema/projects#data-source-runtimevar).

<Tabs
defaultValue="aws-secret-manager"
values={[
{label: 'AWS Secret Manager', value: 'aws-secret-manager'},
{label: 'AWS Systems Manager Parameter Store', value: 'aws-parameter-store'},
{label: 'GCP Secret Manager', value: 'gcp-secret-manager'},
]}>
<TabItem value="aws-secret-manager">

1. Create a secret a secret to store the database password using the AWS CLI:

    ```bash
    aws secretsmanager create-secret \
      --name db-pass-demo \
      --secret-string "p455w0rd"
    ```

    The CLI prints out:

    ```text
    {
        "ARN": "arn:aws:secretsmanager:us-east-1:1111111111:secret:db-pass-demo-aBiM5k",
        "Name": "db-pass-demo",
        "VersionId": "b702431d-174f-4a8f-aee5-b80e687b8bf1"
    }
    ```

    Note the database secret name and the region (`us-east-1`), we will use them in the next part.

2. Create a new file named `atlas.hcl` with the following contents:

    ```hcl
    data "runtimevar" "pass" {
      url = "awssecretsmanager://db-pass-demo?region=us-east-1"
    }

    env "dev" {
      url = "mysql://root:${data.runtimevar.pass}@host:3306/database"
    }
    ```

    Let's breakdown the configuration:
    * The `runtimevar` data source is used to retrieve the database password from AWS Secrets Manager.
    * We define an `env` named `dev`.  The value retrieved by the `runtimevar` data source
       is interpolated into the `url` attribute using the `${data.runtimevar.pass}` expression.

3. Run `atlas schema inspect --env dev` to verify that Atlas is able to connect to the database.

</TabItem>
<TabItem value="aws-parameter-store">

1. Create a encrypted parameter to store the database password using the AWS CLI:

    ```bash
    aws ssm put-parameter \
      --name "db-pass-demo" \
      --value "p455w0rd" \
      --region "us-east-1" \
      --type "SecureString" \
      --tags "Key=Env,Value=AtlasDemo"
    ```

    The CLI prints out:

    ```text
    {
        "Version": 1,
        "Tier": "Standard"
    }
    ```

    Note the database parameter name and the region (`us-east-1`), we will use them in the next part.

2. Create a new file named `atlas.hcl` with the following contents:

    ```hcl
    data "runtimevar" "pass" {
      url = "awsparamstore://db-pass-demo?region=us-east-1&decoder=string"
    }

    env "dev" {
      url = "mysql://root:${data.runtimevar.pass}@host:3306/database"
    }
    ```

    Let's breakdown the configuration:
    * The `runtimevar` data source is used to retrieve the database password from AWS Parameter Store.
    * We define an `env` named `dev`.  The value retrieved by the `runtimevar` data source
       is interpolated into the `url` attribute using the `${data.runtimevar.pass}` expression.

3. Run `atlas schema inspect --env dev` to verify that Atlas is able to connect to the database.

</TabItem>
<TabItem value="gcp-secret-manager">

1. Create a secret a secret to store the database password using the GCP CLI:

    ```bash
    printf "p455w0rd" | gcloud secrets create db-pass-demo --data-file=-
    ```

    The CLI prints out:

    ```text
    Created version [1] of the secret [db-pass-demo].
    ```

2. Create a new file named `atlas.hcl` with the following contents:

    ```hcl
    data "runtimevar" "pass" {
      url = "gcpsecretmanager://projects/my-project/secrets/db-pass-demo"
    }

    env "dev" {
      url = "mysql://root:${data.runtimevar.pass}@host:3306/database"
    }
    ```

    Let's breakdown the configuration:
    * The `runtimevar` data source is used to retrieve the database password from GCP Secret Manager. The URL
      is composed of the project and secret name. If you are working locally in a multi-project environment, you
      can find out the name of the active project by running `gcloud config get-value project`.
    * We define an `env` named `dev`.  The value retrieved by the `runtimevar` data source
       is interpolated into the `url` attribute using the `${data.runtimevar.pass}` expression.

3. Run `atlas schema inspect --env dev` to verify that Atlas is able to connect to the database.

</TabItem>
</Tabs>

## Using IAM Authentication

Atlas can retrieve short-lived credentials from the cloud provider and use them to connect to the database. The
passwords are retrieved using special data sources that are specific to each cloud provider.

<Tabs
defaultValue="aws-rds-iam"
values={[
{label: 'aws_rds_token', value: 'aws-rds-iam'},
{label: 'gcp_cloudsql_token', value: 'gcp-cloud-sql-iam'},
]}>
<TabItem value="aws-rds-iam">

1. Enable IAM Authentication for your database. For instructions on how to do this,
   [see the AWS documentation](https://aws.github.io/aws-sdk-go-v2/docs/sdk-utilities/rds/#iam-authentication).

2. Create a database user and grant it permission to authenticate using IAM, see
   [the AWS documentation](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.DBAccounts.html)
   for instructions.

3. Create an IAM role with the "rds-db:connect" permission for the specific database and user. For instructions on how to do this,
   [see the AWS documentation](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.IAMPolicy.html).

4. Create a new file named `atlas.hcl` with the following contents:

    ```hcl
    locals {
      user = "iamuser"
      endpoint = "hostname-of-db.example9y7k.us-east-1.rds.amazonaws.com:5432"
    }

    data "aws_rds_token" "db" {
        region = "us-east-1"
        endpoint = local.endpoint
        username = local.user
    }

    env "rds" {
      url = "postgres://${local.user}:${urlescape(data.aws_rds_token.db)}@${local.endpoint}/postgres"
    }
    ```

    Let's breakdown the configuration:
    * The `aws_rds_token` data source is used to retrieve the database password from AWS Secrets Manager.
    * We define an `env` named `rds`.  The value retrieved by the `aws_rds_token` data source
       is interpolated into the `url` attribute using the `${data.aws_rds_token.db}` expression.

</TabItem>
<TabItem value="gcp-cloud-sql-iam">

The `gcp_cloudsql_token` data source generates a short-lived token for an [GCP CloudSQL](https://cloud.google.com/sql) database
using [IAM Authentication](https://cloud.google.com/sql/docs/mysql/authentication#manual).

To use this data source:

1. Enable IAM Authentication for your database. For instructions on how to do this,
   [see the GCP documentation](https://cloud.google.com/sql/docs/mysql/create-edit-iam-instances).
2. Create a database user and grant it permission to authenticate using IAM, see
   [the GCP documentation](https://cloud.google.com/sql/docs/mysql/add-manage-iam-users)
   for instructions.
3. Create a file named `atlas.hcl` with the following contents:

    ```hcl title="atlas.hcl"
    locals {
      user = "iamuser"
      endpoint = "34.143.100.1:3306"
    }

    data "gcp_cloudsql_token" "db" {}

    env "cloudsql" {
      url = "mysql://${local.user}:${urlescape(data.gcp_cloudsql_token.db)}@${local.endpoint}/?allowCleartextPasswords=1&tls=skip-verify&parseTime=true"
    }
    ```

    :::note
    The `allowCleartextPasswords` and `tls` parameters are required for the MySQL driver to connect to CloudSQL. For PostgreSQL, use `sslmode=require` to connect to the database.
    :::

    Let's breakdown the configuration:
    * The `gcp_cloudsql_token` data source is used to retrieve the database password from GCP CloudSQL.
    * We define an `env` named `cloudsql`.  The value retrieved by the `gcp_cloudsql_token` data source
       is interpolated into the `url` attribute using the `${data.gcp_cloudsql_token.db}` expression.

</TabItem>
</Tabs>